<template>
  <el-button-group>
    <el-button type="primary" @click="selectFile">
      <slot></slot>
      <span v-if="fileList.data.length">({{ fileList.data.length }})</span>
    </el-button>
    <el-popover placement="bottom-end" :width="200" trigger="hover">
      <template #reference>
        <el-button type="primary" @click="selectFile">
          <el-icon class="el-icon--right" :class="{ active: fileList.data.length }">
            <Upload />
          </el-icon>
        </el-button>
      </template>
      <div class="up-box">
        <div class="title">素材上传列表</div>
        <div class="up-list">
          <div v-for="item in fileList.data" :key="item.key" class="item">
            <div class="name">{{ item.file.name }}</div>
            <div class="status">
              <span v-if="item.status === 1">等待上传</span>
              <span v-if="item.status === 2">{{ item.progress }}%</span>
              <span v-if="item.status === 3">全景制作中</span>
              <span v-if="item.status === 4">上传失败</span>
              <el-button
                v-if="item.status === 4"
                text
                size="small"
                type="danger"
                style="margin-left: 5px"
                @click="doDelete(item)"
                >删除</el-button
              >
            </div>
          </div>
          <div v-if="!fileList.data.length" class="up-list-placeholder">暂无上传文件</div>
        </div>
      </div>
    </el-popover>
  </el-button-group>
  <input type="file" ref="fileBtn" multiple hidden accept="image/*" />
</template>

<script setup lang="ts">
import { ref, reactive, computed, onUnmounted } from 'vue';
import { Upload } from '@element-plus/icons-vue';
import { v4 as uuidv4 } from 'uuid';
import apiMaterial from '@/api/modules/material';
import cookieJs from '@/api/cookie';

const props = defineProps({
  kind: {
    type: Number,
    required: true,
  },
});

const emits = defineEmits(['success']);

type FileListDataType = {
  key: string;
  file: File;
  progress: number;
  status: number;
};

const uniqueKey = ref('');
const fileBtn = ref();
const fileList = reactive<{ data: FileListDataType[] }>({ data: [] });

const ws = new WebSocket(
  `${import.meta.env.VITE_APP_URL.replace(
    /(http|https)/,
    'ws'
  )}/ws/convert?token=${cookieJs.getToken()}`
);

const uploadData = computed(() => fileList.data.filter((item) => item.status !== 4)[0]);

const doUpload = async (data: FileListDataType | undefined) => {
  if (!data) {
    return;
  }
  try {
    const formData = new FormData();
    formData.append('Upload', data.file);
    formData.append('Key', data.key);
    formData.append('Kind', props.kind.toString());
    formData.append('UniqueKey', uniqueKey.value);
    await apiMaterial.commit(formData, (progressEvent) => {
      data.status = 2;
      data.progress = Number(((progressEvent.loaded / progressEvent.total) * 100).toFixed(2));
    });
    data.status = 3;
  } catch (e) {
    data.status = 4;
    doUpload(uploadData.value);
    console.error(e);
  }
};

ws.onopen = () => {
  console.log('ws.open...');
};
ws.onclose = () => {
  console.log('ws.close...');
};

ws.onmessage = function (e) {
  type Data = { UniqueKey?: string; Key?: string; Status?: string; Row?: FileListDataType };
  const data: Data = JSON.parse(e.data);
  if (data.Status === 'Error') {
    const row = fileList.data.find((item) => item.key == data.Key);
    if (row) {
      row.status = 4;
    }
    doUpload(uploadData.value);
    return;
  }
  if (data.Key && data.Row) {
    const index = fileList.data.findIndex((item) => item.key === data.Key);
    fileList.data.splice(index, 1);
    doUpload(uploadData.value);
    emits('success', data.Row);
  }
  if (data.UniqueKey) {
    uniqueKey.value = data.UniqueKey;
  }
};

const buildUploadList = (files: FileList) =>
  fileList.data.concat(
    Array.from(files).map((item) => ({
      file: item,
      progress: 0,
      status: 1,
      key: uuidv4(),
    }))
  );

const selectFile = () => {
  fileBtn.value.click();
  fileBtn.value.onchange = (e: Event) => {
    const files = (e.target as HTMLInputElement).files;
    if (files) {
      fileList.data = buildUploadList(files);
      doUpload(uploadData.value);
    }
    fileBtn.value.value = '';
  };
};

const doDelete = (row: FileListDataType) => {
  const index = fileList.data.findIndex((item) => item.key === row.key);
  fileList.data.splice(index, 1);
};

onUnmounted(() => {
  ws.close();
});
</script>

<style scoped>
:deep(.el-icon.active) {
  animation: uploading 1s ease infinite;
}
@keyframes uploading {
  from {
    transform: translateY(3px);
  }
  to {
    transform: translateY(-3px);
  }
}
.up-box .title {
  padding-bottom: 10px;
  font-weight: bold;
  border-bottom: 1px solid #ddd;
}

.up-list {
  height: 150px;
  overflow-y: auto;
}

.up-list-placeholder {
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #999;
}
.up-list .item {
  padding: 10px 0;
  border-bottom: 1px dashed #ddd;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
</style>
